home *** CD-ROM | disk | FTP | other *** search
/ Compendium Deluxe 1 / LSD Compendium Deluxe 1.iso / a / text / manipulation / cv.lha / cv / cvt / filecopy.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-31  |  6.9 KB  |  296 lines

  1. /*
  2.  *  FILECOPY.C
  3.  *
  4.  *  (c)Copyright 1990,93 by Tobias Ferber,  All Rights Reserved.
  5.  */
  6.  
  7. #include <stdlib.h>
  8. #include <stdio.h>
  9. #include "filecopy.h"
  10.  
  11. #ifdef AMIGA
  12. #include <exec/types.h>
  13. #include <exec/memory.h>
  14. #endif /* AMIGA */
  15.  
  16. /* private statics */
  17. static uchar *copybuffer= (uchar *)0L;
  18. static ulong buffersize= 0L;
  19.  
  20. static char rcs_id[]= "$Id: filecopy.c 1.2 93/09/19 21:33:11 tf Exp $";
  21.  
  22. /*
  23.  *
  24.  * FUNCTION
  25.  *
  26.  *   fc_setbuf -- allocate or free a copy buffer for filecopy()
  27.  *
  28.  * SYNOPSIS
  29.  *   #include "filecopy.h"
  30.  *
  31.  *   result= fc_setbuf(numbytes)
  32.  *   ulong result;
  33.  *   ulong numbytes;
  34.  *
  35.  * DESCRIPTION
  36.  *
  37.  *   This function tries to allocate 'numbytes' bytes for the local
  38.  *   copy buffer.  If you pass 0L with the 'numbytes' parameter the
  39.  *   actual copy buffer will be free()d.
  40.  *   The current size of the copy buffer will be returned.
  41.  *
  42.  * NOTE
  43.  *
  44.  *   It is absolutely legal to re-size your copy buffer by calling this
  45.  *   function only once (with your new buffer size) instead of calling
  46.  *   it twice (with numbytes==0L first)
  47.  *   Note also that this function does *NOT* check whether 'numbytes'
  48.  *   is larger than the local limit. (see "filecopy.h")
  49.  *
  50.  * SEE ALSO
  51.  *
  52.  *   filecopy(), "filecopy.h"
  53.  *
  54.  */
  55.  
  56. ulong fc_setbuf(numbytes)
  57. ulong numbytes;
  58. {
  59. #ifdef AMIGA
  60.   if(copybuffer && buffersize)
  61.     FreeMem(copybuffer, buffersize);
  62.  
  63. #else /* !AMIGA */
  64.   if(copybuffer)
  65.     free(copybuffer);
  66.  
  67. #endif /* AMIGA */
  68.  
  69.   copybuffer= (uchar *)0L;
  70.   buffersize= 0L;
  71.  
  72.  
  73.   if(numbytes)
  74.   {
  75.  
  76. #ifdef AMIGA
  77.     copybuffer= (uchar *)AllocMem(numbytes*sizeof(uchar), MEMF_PUBLIC);
  78.  
  79. #else /* !AMIGA */
  80.     copybuffer= (uchar *)malloc(numbytes*sizeof(uchar));
  81.  
  82. #endif /* AMIGA */
  83.  
  84.     if(copybuffer)
  85.       buffersize= numbytes*sizeof(uchar);
  86.   }
  87.   return buffersize;
  88. }
  89.  
  90. /*
  91. */
  92.  
  93. #ifdef DEBUG
  94. /* My favorite way of reporting that we're alive: */
  95. static void turn(on)
  96. int on;
  97. {
  98.   static char bars[]= "|/-\\|/-\\";
  99.   static int b= 0;
  100.  
  101.   if(on)
  102.   {
  103.     fprintf(stderr,"%c\b",bars[b++]);
  104.  
  105.     if(b >= sizeof(bars)-1)
  106.       b= 0;
  107.   }
  108.   else fprintf(stderr," \b");
  109.  
  110.   fflush(stderr);
  111. }
  112.  
  113. #endif /* DEBUG */
  114.  
  115.  
  116. /*
  117.  *
  118.  * FUNCTION
  119.  *
  120.  *   filecopy -- copy n bytes of data from one file pointer to another
  121.  *
  122.  * SYNOPSIS
  123.  *   #include "filecopy.h"
  124.  *
  125.  *   result= filecopy(src, dst, n)
  126.  *   long result;
  127.  *   long n;
  128.  *   FILE *src, *dst;
  129.  *
  130.  * DESCRIPTION
  131.  *
  132.  *   This function tries to copy 'n' bytes from given source stream 'src'
  133.  *   to the destination 'dst'.
  134.  *   If 'n' is == 0 then filecopy() will compute this value assuming that
  135.  *   all data following the current position of 'src' is ment to be copied.
  136.  *   If a copy buffer has been allocated successfully via fc_setbuf() then
  137.  *   filecopy() will take advantage of of it.  On the other hand, if no
  138.  *   buffer was allocated it will do so on it's own and tries to get either
  139.  *   'n' or (if 'n' is too large) MAXIMUM_BUFFERSIZE bytes.  (See the notes
  140.  *   about this value in "filecopy.h".)
  141.  *   If the allocation fails then filecopy() will copy your data byte for
  142.  *   byte.  Normally the number of written bytes will be returned but
  143.  *
  144.  * NOTE
  145.  *
  146.  *   This function tries to be very careful concerning errors.  If an error
  147.  *   occurs it will exit immediately returning either -1L in case of a read
  148.  *   error in the 'src' file or -2L in case of a write error with the 'dst'
  149.  *   file pointer.
  150.  *   Also filecopy() will *NOT* print out anything, even not if there was
  151.  *   an error.  (There may of course be some output if your OS feels a need
  152.  *   to do so.) It's up to the caller to use perror() or sth. similar to
  153.  *   inform the user about what went wrong.
  154.  *
  155.  * NOTE ALSO
  156.  *
  157.  *   This function assumes 'src' not to be a tty; especially not if you pass
  158.  *   n=0 with the arguments.  In other words, filecopy() will fail if seeking
  159.  *   with 'src' is impossible.
  160.  *   You can however pass a value n<0 in order to force a byte for byte
  161.  *   transfer without seeking.
  162.  *
  163.  */
  164.  
  165. long filecopy(src, dst, n)
  166. long n;
  167. FILE *src, *dst;
  168. {
  169.   long result= 0L;     /* The value returned by this function:
  170.                         * if non-negative the #of bytes written,
  171.                         * -1 = read error,  -2 = write error */
  172.  
  173.   ulong remember= 0L;  /* #of bytes allocated by *this* function */
  174.   long bytesleft= 0L;  /* #of bytes left for copying */
  175.  
  176.   if(n==0)
  177.   {
  178.     /* Compute the #of bytes left for copying */
  179.  
  180. #ifdef BUGGY_FTELL
  181.     do {
  182.       (void)fgetc(src);
  183.       if(!feof(src))
  184.         ++bytesleft;
  185.     } while(!feof(src) || ferror(src))
  186.  
  187. #else /* ftell() works fine */
  188.     if( fseek(src,0L,2L) >= 0) /* 2 == OFFSET_END */
  189.       bytesleft= ftell(src);
  190.     else
  191.       result= -1L;
  192.  
  193. #endif /* BUGGY_FTELL */
  194.  
  195.     if(!ferror(src) && bytesleft>0)
  196.     { if(fseek(src,-bytesleft,1L) < 0) /* 1 == OFFSET_CURRENT */
  197.         result= -1L;
  198.     }
  199.     else result= -1L;
  200.   }
  201.   else /* n!=0 */
  202.     bytesleft= (n > 0) ? n : 0L;
  203.  
  204.  
  205.   if(!result)
  206.   {
  207.     long nbytes= 0L;
  208.  
  209.     if(!copybuffer && bytesleft>0)
  210.     {
  211.       remember= fc_setbuf( (bytesleft > MAXIMUM_BUFFERSIZE) ?
  212.         MAXIMUM_BUFFERSIZE : bytesleft );
  213.     }
  214.  
  215.     /* If the allocation failed (or if n was negative) then we'll copy
  216.      * the data byte for byte which of course is hyper slow ;)
  217.      */
  218.  
  219.     if(!copybuffer || buffersize < 2L)
  220.     {
  221.       uchar c;
  222.       int done= 0;
  223.  
  224.       do {
  225.         c= fgetc(src);
  226.         if(!feof(src))
  227.         { fputc(c,dst);
  228.           nbytes++;
  229.           if(n>0 && nbytes>=n)
  230.             done= 1;
  231. #ifdef DEBUG
  232.           turn(1);
  233. #endif /* DEBUG */
  234.         }
  235.       } while(!done && !feof(src) && !ferror(src) && !ferror(dst));
  236.  
  237.       /* This might change later when checking ferror(): */
  238.       result= nbytes;
  239.     }
  240.  
  241.     else /* use the buffer */
  242.     {
  243.       long psize;  /* packet size */
  244.  
  245.       do {
  246.         psize= (bytesleft > buffersize) ? buffersize : bytesleft;
  247.         bytesleft-= psize;
  248.  
  249.         /* I think it's a good idea to use fread() and fwrite() with
  250.          * psize packets of size 1 here instead of 1 packet of size psize
  251.          * because these functions return the number of *complete* packets
  252.          * that were read (or written).  This way we can also handle
  253.          * partial packets if needed. */
  254.  
  255.         nbytes= fread(copybuffer, 1L, psize, src);
  256.  
  257.         if(!ferror(src))
  258.         {
  259.           /* write exactly as many bytes as we read before */
  260.  
  261.           nbytes= fwrite(copybuffer, 1L, nbytes, dst);
  262.           result += nbytes;
  263.         }
  264.  
  265.         /* A partial read or written packet indicates that we're done,
  266.          * it does however not neccessarily mean that there was an error.
  267.          * Changing the result to a negative value can be done later
  268.          * by testing ferror(). */
  269.  
  270.         if(nbytes!=psize)
  271.           bytesleft= 0;
  272.  
  273. #ifdef DEBUG
  274.         turn(1);
  275. #endif
  276.  
  277.       } while(bytesleft>0 && !ferror(src) && !ferror(dst));
  278.     }
  279.  
  280.     if(ferror(src))
  281.       result= -1L;
  282.     else if(ferror(dst))
  283.       result= -2L;
  284.   }
  285.  
  286.   /* free the copy buffer if it was allocated by us */
  287.   if(remember)
  288.     fc_setbuf(0L);
  289.  
  290. #ifdef DEBUG
  291.   turn(0);
  292. #endif
  293.  
  294.   return result;
  295. }
  296.